home *** CD-ROM | disk | FTP | other *** search
/ The PC-SIG Library 10 / The PC-Sig Library - Shareware for the IBM PC and Compatibles (PC-SIG)(Tenth Edition Disks 1-2804)(1991).iso / PC_SIGCD / 22 / 4 / DISK2247.ZIP / CBASE101.ZIP / ROLODECK.ZIP / ROLODECK.C < prev    next >
Text File  |  1990-06-21  |  23KB  |  734 lines

  1. /*    Copyright (c) 1989 Citadel    */
  2. /*       All Rights Reserved        */
  3.  
  4. /* #ident    "@(#)rolodeck.c    1.4 - 90/06/21" */
  5.  
  6. /* ansi headers */
  7. #include <ctype.h>
  8. #include <errno.h>
  9. #include <stdio.h>
  10. /*#include <stdlib.h>*/
  11. /*#include <string.h>*/
  12.  
  13. /* library headers */
  14. #include <blkio.h>
  15. #include <cbase.h>
  16.  
  17. /* local headers */
  18. #include "basstr.h"
  19. #include "rolodeck.h"
  20. #include "rolodeck.i"
  21.  
  22. #ifndef EXIT_SUCCESS
  23. #define EXIT_SUCCESS    (0)
  24. #define EXIT_FAILURE    (1)
  25. #endif
  26.  
  27. /* constants */
  28. #define EXPFILE        ("rolodeck.txt")    /* export file */
  29. #define LMAXTRIES    (100)            /* maximum lock tries */
  30. #define USAGE        ("Usage: rolodeck")    /* usage message */
  31.                         /* rolodeck user requests */
  32. #define RD_REQ_NEXT_CARD    ('N')        /* next card */
  33. #define RD_REQ_PREV_CARD    ('P')        /* previous card */
  34. #define RD_REQ_FIRST_CARD    ('F')        /* first card*/
  35. #define RD_REQ_LAST_CARD    ('L')        /* last card */
  36. #define RD_REQ_INS_CARD        ('I')        /* insert card */
  37. #define RD_REQ_DEL_CARD        ('D')        /* delete card */
  38. #define RD_REQ_SRCH_CARD    ('S')        /* search for card */
  39. #define RD_REQ_TOG_SORT        ('T')        /* toggle sort field */
  40. #define RD_REQ_CUR_CARD        ('C')        /* current card */
  41. #define RD_REQ_ALL_CARDS    ('A')        /* all cards */
  42. #define RD_REQ_IMPORT        ('M')        /* import cards */
  43. #define RD_REQ_EXPORT        ('X')        /* export cards */
  44. #define RD_REQ_HELP        ('H')        /* help */
  45. #define RD_REQ_QUIT        ('Q')        /* quit */
  46.  
  47. /* function declarations */
  48. #ifdef AC_PROTO
  49. int fmltolfm(char *t, const char *s, size_t n);
  50. int lfmtofml(char *t, const char *s, size_t n);
  51. int getcard(rolodeck_t *rdp);
  52. int putcard(const rolodeck_t *rdp);
  53. int putmenu(int sf);
  54. int rdlock(cbase_t *cbp, int ltype);
  55. #else
  56. int fmltolfm();
  57. int lfmtofml();
  58. int getcard();
  59. int putcard();
  60. int putmenu();
  61. int rdlock();
  62. #endif
  63.  
  64. /*man---------------------------------------------------------------------------
  65. NAME
  66.     rolodeck - card file
  67.  
  68. SYNOPSIS
  69.      rolodeck
  70.  
  71. DESCRIPTION
  72.      rolodeck is an example program for the cbase library.  In order
  73.      to allow it to be compiled without requiring a specific screen
  74.      management library, only a minimal user interface has been
  75.      implemented.
  76.  
  77. NOTES
  78.      Below are listed a few of the more important points to note when
  79.      examining the rolodeck source code.
  80.  
  81.           o White space is significant in string data.  For
  82.             instance, " data" != "data".  Leading and
  83.             trailing white space is therefore usually
  84.             removed before storing a string in a database.
  85.             Also, embedded white space may be reduced to a
  86.             single space.  The cvtss function included with
  87.             cbase will perform these string operations.
  88.           o Names are often input and displayed
  89.             first-name-first.  For them to sort correctly in
  90.             a database, however, they must be stored
  91.             last-name-first.  The functions fmltolfm and
  92.             lfmtofml are included with cbase to convert
  93.             between these two formats.
  94.           o bexit is used in place of exit to prevent loss
  95.             of buffered data.
  96.  
  97.      The following notes concern locking.
  98.  
  99.           o Single-tasking applications can simply lock
  100.             a cbase and leave it locked.
  101.           o Locks are held for shortest time possible; a
  102.             lock is never held during user input.
  103.           o A write lock should not be used when only a read
  104.             lock is required.
  105.           o When a database file is unlocked, it may be
  106.             modified by another process.  A record at a
  107.             given file position may be deleted, and the
  108.             empty slot possibly reused for a new record.
  109.             Because of this, each time a file is locked,
  110.             the current record must be located by performing
  111.             a search on a unique key.
  112.           o If locking multiple cbases, deadlock must be
  113.             avoided (see The cbase Programmer's Guide).
  114.  
  115. ------------------------------------------------------------------------------*/
  116. int main(argc, argv)
  117. int argc;
  118. char *argv[];
  119. {
  120.     char        buf[256];        /* gp input buffer */
  121.     cbase_t *    cbp    = NULL;        /* cbase pointer */
  122.     int        found    = 0;        /* search flag */
  123.     rolodeck_t    rd;            /* rolodeck record */
  124.     int        rq    = 0;        /* user request */
  125.     int        sf    = 0;        /* sort field */
  126.  
  127.     /* process command line options and arguments */
  128.     if (argc != 1) {
  129.         puts(USAGE);
  130.         bexit(EXIT_FAILURE);
  131.     }
  132.  
  133.     /* open rolodeck cbase */
  134.     cbp = cbopen(ROLODECK, "r+", RDFLDC, rdfldv);
  135.     if (cbp == NULL) {
  136.         if (errno != ENOENT) {
  137.             fprintf(stderr, "*** Error %d opening rolodeck.\n", errno);
  138.             bexit(EXIT_FAILURE);
  139.         }
  140.         /* create rolodeck cbase */
  141.         puts("Rolodeck does not exist.  Creating...");
  142.         if (cbcreate(ROLODECK, sizeof(rolodeck_t), RDFLDC, rdfldv) == -1) {
  143.             fprintf(stderr, "*** Error %d creating rolodeck.\n", errno);
  144.             bexit(EXIT_FAILURE);
  145.         }
  146.         cbp = cbopen(ROLODECK, "r+", RDFLDC, rdfldv);
  147.         if (cbp == NULL) {
  148.             fprintf(stderr, "*** Error %d opening rolodeck.\n", errno);
  149.             bexit(EXIT_FAILURE);
  150.         }
  151.     }
  152.     if (cbrecsize(cbp) != sizeof(rolodeck_t)) {
  153.         fprintf(stderr, "*** PANIC: incorrect record size.\n");
  154.         bexit(EXIT_FAILURE);
  155.     }
  156.  
  157.     puts("\n--------------------------------------------------");
  158.     puts("|                    Rolodeck                    |");
  159.     puts("--------------------------------------------------\n");
  160.  
  161.     /* set sort field */
  162.     sf = RD_CONTACT;
  163.  
  164.     /* display menu */
  165.     putmenu(sf);
  166.  
  167.     /* main loop */
  168.     memset(&rd, 0, sizeof(rd));
  169.     for (;;) {
  170.         fputs("Enter selection:  ", stdout);
  171.         fgets(buf, (int)sizeof(buf), stdin);
  172.         cvtss(buf, buf, CVT_XSP | CVT_XCTL, sizeof(buf));
  173.         rq = toupper(*buf);
  174.         if (rq == RD_REQ_QUIT) {    /* quit rolodeck */
  175.             break;
  176.         }
  177.         if (rq == NUL) {        /* default to next card */
  178.             rq = RD_REQ_NEXT_CARD;
  179.         }
  180.         switch (rq) {
  181.         case RD_REQ_NEXT_CARD:    /* next card */
  182.             if (rdlock(cbp, CB_RDLCK) == -1) {
  183.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  184.                 bexit(EXIT_FAILURE);
  185.             }
  186.             if (cbreccnt(cbp) == 0) {
  187.                 puts("The rolodeck is empty.\n");
  188.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  189.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  190.                     bexit(EXIT_FAILURE);
  191.                 }
  192.                 continue;
  193.             }
  194.             /* use unique key field to set record cursor */
  195.             found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  196.             if (found == -1) {
  197.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  198.                 bexit(EXIT_FAILURE);
  199.             }
  200.             /* align cursor of sort key */
  201.             if (cbkeyalign(cbp, sf) == -1) {
  202.                 fprintf(stderr, "*** Error %d aligning key.\n", errno);
  203.                 bexit(EXIT_FAILURE);
  204.             }
  205.             if (found == 1) {
  206.                 /* advance key (and rec) cursor 1 position */
  207.                 if (cbkeynext(cbp, sf) == -1) {
  208.                     fprintf(stderr, "*** Error %d finding next card.\n", errno);
  209.                     bexit(EXIT_FAILURE);
  210.                 }
  211.             }
  212.             if (cbrcursor(cbp) == NULL) {
  213.                 puts("End of deck.\n");
  214.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  215.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  216.                     bexit(EXIT_FAILURE);
  217.                 }
  218.                 continue;
  219.             }
  220.             if (cbgetr(cbp, &rd) == -1) {
  221.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  222.                 bexit(EXIT_FAILURE);
  223.             }
  224.             if (rdlock(cbp, CB_UNLCK) == -1) {
  225.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  226.                 bexit(EXIT_FAILURE);
  227.             }
  228.             putcard(&rd);
  229.             break;    /* case RD_REQ_NEXT_CARD: */
  230.         case RD_REQ_PREV_CARD:    /* previous card */
  231.             if (rdlock(cbp, CB_RDLCK) == -1) {
  232.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  233.                 bexit(EXIT_FAILURE);
  234.             }
  235.             if (cbreccnt(cbp) == 0) {
  236.                 puts("The rolodeck is empty.\n");
  237.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  238.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  239.                     bexit(EXIT_FAILURE);
  240.                 }
  241.                 continue;
  242.             }
  243.             /* use unique key field to set record cursor */
  244.             found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  245.             if (found == -1) {
  246.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  247.                 bexit(EXIT_FAILURE);
  248.             }
  249.             /* align cursor of sort key */
  250.             if (cbkeyalign(cbp, sf) == -1) {
  251.                 fprintf(stderr, "*** Error %d aligning key.\n", errno);
  252.                 bexit(EXIT_FAILURE);
  253.             }
  254.             /* retreat key (and rec) cursor 1 position */
  255.             if (cbkeyprev(cbp, sf) == -1) {
  256.                 fprintf(stderr, "*** Error %d finding previous card.\n", errno);
  257.                 bexit(EXIT_FAILURE);
  258.             }
  259.             if (cbrcursor(cbp) == NULL) {
  260.                 puts("Beginning of deck.\n");
  261.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  262.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  263.                     bexit(EXIT_FAILURE);
  264.                 }
  265.                 continue;
  266.             }
  267.             if (cbgetr(cbp, &rd) == -1) {
  268.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  269.                 bexit(EXIT_FAILURE);
  270.             }
  271.             if (rdlock(cbp, CB_UNLCK) == -1) {
  272.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  273.                 bexit(EXIT_FAILURE);
  274.             }
  275.             putcard(&rd);
  276.             break;    /* case RD_REQ_PREV_CARD: */
  277.         case RD_REQ_FIRST_CARD:    /* first card */
  278.             if (rdlock(cbp, CB_RDLCK) == -1) {
  279.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  280.                 bexit(EXIT_FAILURE);
  281.             }
  282.             if (cbreccnt(cbp) == 0) {
  283.                 puts("The rolodeck is empty.\n");
  284.                 if(rdlock(cbp, CB_UNLCK) == -1) {
  285.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  286.                     bexit(EXIT_FAILURE);
  287.                 }
  288.                 continue;
  289.             }
  290.             if (cbkeyfirst(cbp, sf) == -1) {
  291.                 fprintf(stderr, "*** Error %d finding first card.\n", errno);
  292.                 bexit(EXIT_FAILURE);
  293.             }
  294.             if (cbgetr(cbp, &rd) == -1) {
  295.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  296.                 bexit(EXIT_FAILURE);
  297.             }
  298.             if (rdlock(cbp, CB_UNLCK) == -1) {
  299.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  300.                 bexit(EXIT_FAILURE);
  301.             }
  302.             putcard(&rd);
  303.             break;    /* case RD_REQ_FIRST_CARD: */
  304.         case RD_REQ_LAST_CARD:    /* last card */
  305.             if (rdlock(cbp, CB_RDLCK) == -1) {
  306.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  307.                 bexit(EXIT_FAILURE);
  308.             }
  309.             if (cbreccnt(cbp) == 0) {
  310.                 puts("The rolodeck is empty.\n");
  311.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  312.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  313.                     bexit(EXIT_FAILURE);
  314.                 }
  315.                 continue;
  316.             }
  317.             if (cbkeylast(cbp, sf) == -1) {
  318.                 fprintf(stderr, "*** Error %d finding last card.\n", errno);
  319.                 bexit(EXIT_FAILURE);
  320.             }
  321.             if (cbgetr(cbp, &rd) == -1) {
  322.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  323.                 bexit(EXIT_FAILURE);
  324.             }
  325.             if (rdlock(cbp, CB_UNLCK) == -1) {
  326.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  327.                 bexit(EXIT_FAILURE);
  328.             }
  329.             putcard(&rd);
  330.             break;    /* case RD_REQ_LAST_CARD: */
  331.         case RD_REQ_INS_CARD:    /* insert new card */
  332.             getcard(&rd);
  333.             if (strlen(rd.rd_contact) == 0) {
  334.                 puts("Contact name cannot be blank.  Card not inserted.\n");
  335.                 memset(&rd, 0, sizeof(rd));
  336.                 continue;
  337.             }
  338.             if (rdlock(cbp, CB_WRLCK) == -1) {
  339.                 fprintf(stderr, "*** Error %d write locking rolodeck.\n", errno);
  340.                 bexit(EXIT_FAILURE);
  341.             }
  342.             if (cbinsert(cbp, &rd) == -1) {
  343.                 if (errno == CBEDUP) {
  344.                     printf("%s is already in the rolodeck.\n\n", rd.rd_contact);
  345.                     if (rdlock(cbp, CB_UNLCK) == -1) {
  346.                         fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  347.                         bexit(EXIT_FAILURE);
  348.                     }
  349.                     continue;
  350.                 }
  351.                 fprintf(stderr, "*** Error %d inserting card.\n", errno);
  352.                 bexit(EXIT_FAILURE);
  353.             }
  354.             if (rdlock(cbp, CB_UNLCK) == -1) {
  355.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  356.                 bexit(EXIT_FAILURE);
  357.             }
  358.             putcard(&rd);
  359.             break;    /* case RD_REQ_INS_CARD: */
  360.         case RD_REQ_DEL_CARD:    /* delete current card */
  361.             if (rdlock(cbp, CB_WRLCK) == -1) {
  362.                 fprintf(stderr, "*** Error %d write locking rolodeck.\n", errno);
  363.                 bexit(EXIT_FAILURE);
  364.             }
  365.             /* use unique key field to set record cursor */
  366.             found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  367.             if (found == -1) {
  368.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  369.                 bexit(EXIT_FAILURE);
  370.             }
  371.             if (found == 0) {
  372.                 puts("There is no current card.\n");
  373.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  374.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  375.                     bexit(EXIT_FAILURE);
  376.                 }
  377.                 continue;
  378.             }
  379.             /* delete record */
  380.             if (cbdelcur(cbp) == -1) {
  381.                 fprintf(stderr, "*** Error %d deleting current card.\n", errno);
  382.                 bexit(EXIT_FAILURE);
  383.             }
  384.             lfmtofml(buf, rd.rd_contact, sizeof(buf));
  385.             printf("%s deleted from rolodeck.\n\n", buf);
  386.             /* new current record */
  387.             switch (sf) {
  388.             default:
  389.                 sf = RD_CONTACT;
  390.             case RD_CONTACT:
  391.                 found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  392.                 if (found == -1) {
  393.                     fprintf(stderr, "*** Error %d searching for key.\n", errno);
  394.                     bexit(EXIT_FAILURE);
  395.                 }
  396.                 break;
  397.             case RD_COMPANY:
  398.                 found = cbkeysrch(cbp, RD_COMPANY, rd.rd_company);
  399.                 if (found == -1) {
  400.                     fprintf(stderr, "*** Error %d searching for key.\n", errno);
  401.                     bexit(EXIT_FAILURE);
  402.                 }
  403.                 break;
  404.             }
  405.             /* load rd with new current card */
  406.             if (cbrcursor(cbp) == NULL) {
  407.                 memset(&rd, 0, sizeof(rd));
  408.             } else {
  409.                 if (cbgetr(cbp, &rd) == -1) {
  410.                     fprintf(stderr, "*** Error %d reading card.\n", errno);
  411.                     bexit(EXIT_FAILURE);
  412.                 }
  413.             }
  414.             if (rdlock(cbp, CB_UNLCK) == -1) {
  415.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  416.                 bexit(EXIT_FAILURE);
  417.             }
  418.             break;    /* case RD_REQ_DEL_CARD: */
  419.         case RD_REQ_SRCH_CARD:    /* search for card */
  420.             if (sf == RD_CONTACT) {
  421.                 fputs("Enter contact name:  ", stdout);
  422.             } else {
  423.                 fputs("Enter company name:  ", stdout);
  424.             }
  425.             if (fgets(buf, sizeof(buf), stdin) == NULL) {
  426.                 fprintf(stderr, "*** Error %d reading input.\n");
  427.                 bexit(EXIT_FAILURE);
  428.             }
  429.             cvtss(buf, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(buf));
  430.             if (sf == RD_CONTACT) {
  431.                 fmltolfm(buf, buf, sizeof(buf));
  432.             }
  433.             /* don't lock until after user input */
  434.             if (rdlock(cbp, CB_RDLCK) == -1) {
  435.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  436.                 bexit(EXIT_FAILURE);
  437.             }
  438.             if (cbreccnt(cbp) == 0) {
  439.                 puts("The rolodeck is empty.\n");
  440.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  441.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  442.                     bexit(EXIT_FAILURE);
  443.                 }
  444.                 continue;
  445.             }
  446.             found = cbkeysrch(cbp, sf, buf);
  447.             if (found == -1) {
  448.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  449.                 bexit(EXIT_FAILURE);
  450.             }
  451.             if (found == 0) {
  452.                 printf("%s not found.\n\n", buf);
  453.                 if (cbrcursor(cbp) == NULL) {
  454.                     if (cbkeylast(cbp, sf) == -1) {
  455.                         fprintf(stderr, "*** Error %d finding last card.\n", errno);
  456.                         bexit(EXIT_FAILURE);
  457.                     }
  458.                 }
  459.             }
  460.             if (cbgetr(cbp, &rd) == -1) {
  461.                 fprintf(stderr, "*** Error %d reading card.\n", errno);
  462.                 bexit(EXIT_FAILURE);
  463.             }
  464.             if (rdlock(cbp, CB_UNLCK) == -1) {
  465.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  466.                 bexit(EXIT_FAILURE);
  467.             }
  468.             putcard(&rd);
  469.             break;    /* case RD_REQ_SRCH_CARD: */
  470.         case RD_REQ_TOG_SORT:    /* toggle sort field */
  471.             switch (sf) {
  472.             case RD_CONTACT:
  473.                 sf = RD_COMPANY;
  474.                 break;
  475.             case RD_COMPANY:
  476.                 sf = RD_CONTACT;
  477.                 break;
  478.             default:
  479.                 sf = RD_CONTACT;
  480.                 break;
  481.             }
  482.             putmenu(sf);
  483.             break;    /* case RD_REQ_TOG_SORT: */
  484.         case RD_REQ_CUR_CARD:    /* display current card */
  485.             if (strlen(rd.rd_contact) == 0) {
  486.                 puts("There is no current card.\n");
  487.                 continue;
  488.             }
  489.             if (rdlock(cbp, CB_RDLCK) == -1) {
  490.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  491.                 bexit(EXIT_FAILURE);
  492.             }
  493.             /* use unique key field to set record cursor */
  494.             found = cbkeysrch(cbp, RD_CONTACT, rd.rd_contact);
  495.             if (found == -1) {
  496.                 fprintf(stderr, "*** Error %d searching for key.\n", errno);
  497.                 bexit(EXIT_FAILURE);
  498.             }
  499.             /* check if card deleted by other process */
  500.             if (found == 0) {
  501.                 puts("There is no current card.\n");
  502.             } else {
  503.                 if (cbgetr(cbp, &rd) == -1) {
  504.                     fprintf(stderr, "*** Error %d reading card.\n", errno);
  505.                     bexit(EXIT_FAILURE);
  506.                 }
  507.                 putcard(&rd);
  508.             }
  509.             if (rdlock(cbp, CB_UNLCK) == -1) {
  510.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  511.                 bexit(EXIT_FAILURE);
  512.             }
  513.             break;    /* case RD_REQ_CUR_CARD: */
  514.         case RD_REQ_ALL_CARDS:    /* display all cards */
  515.             if (rdlock(cbp, CB_RDLCK) == -1) {
  516.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  517.                 bexit(EXIT_FAILURE);
  518.             }
  519.             if (cbreccnt(cbp) == 0) {
  520.                 puts("The rolodeck is empty.\n");
  521.                 if (rdlock(cbp, CB_UNLCK) == -1) {
  522.                     fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  523.                     bexit(EXIT_FAILURE);
  524.                 }
  525.                 continue;
  526.             }
  527.             if (cbkeyfirst(cbp, sf) == -1) {
  528.                 fprintf(stderr, "*** Error %d setting key cursor.\n", errno);
  529.                 bexit(EXIT_FAILURE);
  530.             }
  531.             while (cbkcursor(cbp, sf) != NULL) {
  532.                 if (cbgetr(cbp, &rd) == -1) {
  533.                     fprintf(stderr, "*** Error %d reading card.\n", errno);
  534.                     bexit(EXIT_FAILURE);
  535.                 }
  536.                 putcard(&rd);
  537.                 if (cbkeynext(cbp, sf) == -1) {
  538.                     fprintf(stderr, "*** Error %d finding next card.\n", errno);
  539.                     bexit(EXIT_FAILURE);
  540.                 }
  541.             }
  542.             if (rdlock(cbp, CB_UNLCK) == -1) {
  543.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  544.                 bexit(EXIT_FAILURE);
  545.             }
  546.             break;    /* case RD_REQ_ALL_CARDS: */
  547.         case RD_REQ_IMPORT:    /* import cards */
  548.             if (rdlock(cbp, CB_WRLCK) == -1) {
  549.                 fprintf(stderr, "*** Error %d write locking rolodeck.\n", errno);
  550.                 bexit(EXIT_FAILURE);
  551.             }
  552.             printf("Importing cards from %s....\n", EXPFILE);
  553.             if (cbimport(cbp, EXPFILE) == -1) {
  554.                 if (errno == ENOENT) {
  555.                     puts("Text file not found.\n");
  556.                 } else if (errno == CBEDUP) {
  557.                     puts("WARNING:  Duplicate card(s) in text file not imported.\n");
  558.                 } else {
  559.                     fprintf(stderr, "*** Error %d importing rolodeck from %s.\n", errno, EXPFILE);
  560.                     bexit(EXIT_FAILURE);
  561.                 }
  562.             } else {
  563.                 puts("Import complete.\n");
  564.             }
  565.             if (rdlock(cbp, CB_UNLCK) == -1) {
  566.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  567.                 bexit(EXIT_FAILURE);
  568.             }
  569.             break;    /* cbase RD_REQ_IMPORT: */
  570.         case RD_REQ_EXPORT:    /* export cards */
  571.             if (rdlock(cbp, CB_RDLCK) == -1) {
  572.                 fprintf(stderr, "*** Error %d read locking rolodeck.\n", errno);
  573.                 bexit(EXIT_FAILURE);
  574.             }
  575.             printf("Exporting cards to %s....\n", EXPFILE);
  576.             if (cbexport(cbp, EXPFILE) == -1) {
  577.                 fprintf(stderr, "*** Error %d exporting rolodeck to %s.\n", errno, EXPFILE);
  578.                 bexit(EXIT_FAILURE);
  579.             }
  580.             puts("Export complete.\n");
  581.             if (rdlock(cbp, CB_UNLCK) == -1) {
  582.                 fprintf(stderr, "*** Error %d unlocking rolodeck.\n", errno);
  583.                 bexit(EXIT_FAILURE);
  584.             }
  585.             break;    /* cbase RD_REQ_EXPORT: */
  586.         case RD_REQ_HELP:    /* help */
  587.             putmenu(sf);
  588.             continue;
  589.             break;    /* case RD_REQ_HELP: */
  590.         default:
  591.             putchar('\a');    /* beep */
  592.             continue;
  593.             break;    /* default: */
  594.         }
  595.     }
  596.  
  597.     /* close cbase */
  598.     if (cbclose(cbp) == -1) {
  599.         fprintf(stderr, "*** Error %d closing rolodeck.\n", errno);
  600.         bexit(EXIT_FAILURE);
  601.     }
  602.  
  603.     exit(EXIT_SUCCESS);
  604. }
  605.  
  606. /* rdlock:  lock rolodeck */
  607. int rdlock(cbp, ltype)
  608. cbase_t *cbp;
  609. int ltype;
  610. {
  611.     int i = 0;
  612.  
  613.     for (i = 0; i < LMAXTRIES; i++) {
  614.         if (cblock(cbp, ltype) == -1) {
  615.             if (errno == EAGAIN) {
  616.                 continue;
  617.             }
  618.             return -1;
  619.         } else {
  620.             errno = 0;
  621.             return 0;
  622.         }
  623.     }
  624.  
  625.     errno = EAGAIN;
  626.     return -1;
  627. }
  628.  
  629. /* putmenu:  display menu */
  630. int putmenu(sf)
  631. int sf;
  632. {
  633.     puts("-----------------------MENU-----------------------");
  634.     puts("| N - Next card          P - Previous card       |");
  635.     puts("| F - First card         L - Last card           |");
  636.     puts("| I - Insert new card    D - Delete current card |");
  637.     puts("| S - Search for card    T - Toggle sort field   |");
  638.     puts("| C - display Current    A - display All cards   |");
  639.     puts("| M - iMport cards       X - eXport cards        |");
  640.     puts("| H - Help (menu)        Q - Quit                |");
  641.     puts("--------------------------------------------------");
  642.     fputs("current sort field:  ", stdout);
  643.     switch (sf) {
  644.     default:
  645.         sf = RD_CONTACT;
  646.     case RD_CONTACT:
  647.         fputs("contact", stdout);
  648.         break;
  649.     case RD_COMPANY:
  650.         fputs("company", stdout);
  651.         break;
  652.     }
  653.     puts(".\n");
  654.  
  655.     return 0;
  656. }
  657.  
  658. /* getcard:  input card */
  659. int getcard(rdp)
  660. rolodeck_t *rdp;
  661. {
  662.     char buf[256];
  663.     int i = 0;
  664.  
  665.     memset(rdp, 0, sizeof(*rdp));
  666.  
  667.     printf("Contact:  ");
  668.     fgets(buf, sizeof(buf), stdin);
  669.     cvtss(buf, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(buf));
  670.     fmltolfm(rdp->rd_contact, buf, sizeof(rdp->rd_contact));
  671.     printf("Title:  ");
  672.     fgets(buf, sizeof(buf), stdin);
  673.     cvtss(rdp->rd_title, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(rdp->rd_title));
  674.     printf("Company:  ");
  675.     fgets(buf, sizeof(buf), stdin);
  676.     cvtss(rdp->rd_company, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(rdp->rd_company));
  677.     puts("Street Address (2 lines):");
  678.     for (i = 0; i < 2; i++) {
  679.         fgets(buf, sizeof(buf), stdin);
  680.         cvtss(buf, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(buf));
  681.         sprintf(rdp->rd_addr + 40 * i, "%-40.40s", buf);
  682.     }
  683.     printf("City:  ");
  684.     fgets(buf, sizeof(buf), stdin);
  685.     cvtss(rdp->rd_city, buf, CVT_XLEADSP | CVT_XTRAILSP | CVT_1SP | CVT_XCTL, sizeof(rdp->rd_city));
  686.     printf("State:  ");
  687.     fgets(buf, sizeof(buf), stdin);
  688.     cvtss(rdp->rd_state, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_state));
  689.     printf("Zip Code:  ");
  690.     fgets(buf, sizeof(buf), stdin);
  691.     cvtss(rdp->rd_zip, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_zip));
  692.     printf("Phone:  ");
  693.     fgets(buf, sizeof(buf), stdin);
  694.     cvtss(rdp->rd_phone, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_phone));
  695.     printf("Extension:  ");
  696.     fgets(buf, sizeof(buf), stdin);
  697.     cvtss(rdp->rd_ext, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_ext));
  698.     printf("Fax:  ");
  699.     fgets(buf, sizeof(buf), stdin);
  700.     cvtss(rdp->rd_fax, buf, CVT_XSP | CVT_XCTL, sizeof(rdp->rd_fax));
  701.     puts("Notes (4 lines):");
  702.     for (i = 0; i < 4; i++) {
  703.         fgets(buf, sizeof(buf), stdin);
  704.         cvtss(buf, buf, CVT_XCTL, sizeof(buf));
  705.         sprintf(rdp->rd_notes + 40 * i, "%-40.40s", buf);
  706.     }
  707.  
  708.     return 0;
  709. }
  710.  
  711. /* putcard:  display card */
  712. int putcard(rdp)
  713. const rolodeck_t *rdp;
  714. {
  715.     char name[sizeof(rdp->rd_contact)];
  716.  
  717.     lfmtofml(name, rdp->rd_contact, sizeof(name));
  718.     puts("--------------------CARD--------------------");
  719.     printf("| %-40.40s |\n", name);
  720.     printf("| %-40.40s |\n", rdp->rd_title);
  721.     printf("| %-40.40s |\n", rdp->rd_company);
  722.     printf("| %-40.40s |\n", rdp->rd_addr);
  723.     printf("| %-40.40s |\n", rdp->rd_addr + 40);
  724.     printf("| %-25.25s, %-2.2s %-10.10s |\n", rdp->rd_city, rdp->rd_state, rdp->rd_zip);
  725.     printf("| %-12.12s x%-4.4s  fax %-12.12s     |\n", rdp->rd_phone, rdp->rd_ext, rdp->rd_fax);
  726.     printf("| %-40.40s |\n", rdp->rd_notes);
  727.     printf("| %-40.40s |\n", rdp->rd_notes + 40);
  728.     printf("| %-40.40s |\n", rdp->rd_notes + 80);
  729.     printf("| %-40.40s |\n", rdp->rd_notes + 120);
  730.     puts("--------------------------------------------");
  731.  
  732.     return 0;
  733. }
  734.